#ifndef __CASE_TPL_STACK_H__
#define __CASE_TPL_STACK_H__

#include "common_types.h"
#include "basic/tpl_stack.h"

class Test_tpl_stack : public testing::Test {
protected:
  __thread_safe__::tpl_stack<AA> stk;
  __thread_safe__::tpl_stack<AA> stk_done;
  virtual void SetUp(){};
  virtual void TearDown(){};
};

TEST_F(Test_tpl_stack, GetSize_IsEmpty) {
  stk.Push(new AA(1));
  stk.Push(new AA(2));
  stk.Push(new AA(3));
  stk.Push(new AA(4));
  stk.Push(new AA(5));
  ASSERT_EQ(stk.GetSize(), 5);
  AA* pAA = stk.Pop();
  ASSERT_EQ(stk.GetSize(), 4);
  ASSERT_EQ(stk.IsEmpty(), false);
  delete pAA;
  pAA = stk.Pop();
  ASSERT_EQ(stk.GetSize(), 3);
  ASSERT_EQ(stk.IsEmpty(), false);
  delete pAA;
  pAA = stk.Pop();
  ASSERT_EQ(stk.GetSize(), 2);
  ASSERT_EQ(stk.IsEmpty(), false);
  delete pAA;
  pAA = stk.Pop();
  ASSERT_EQ(stk.GetSize(), 1);
  ASSERT_EQ(stk.IsEmpty(), false);
  delete pAA;
  pAA = stk.Pop();
  ASSERT_EQ(stk.GetSize(), 0);
  ASSERT_EQ(stk.IsEmpty(), true);
  delete pAA;
}

TEST_F(Test_tpl_stack, Clear) {
  const int M{10};
  AA* pAA[M];
  for (int i = 0; i < M; ++i) {
    pAA[i] = new AA(i);
    stk.Push(pAA[i]);
  }

  ASSERT_EQ(stk.GetSize(), M);
  stk.Clear();
  ASSERT_EQ(stk.GetSize(), 0);

  for (int i = 0; i < M; ++i) {
    delete pAA[i];
  }
}

TEST_F(Test_tpl_stack, value) {
  stk.Push(new AA(1));
  stk.Push(new AA(2));
  stk.Push(new AA(3));
  AA* pAA = stk.Pop();
  ASSERT_EQ(pAA->GetI(), 3);
  pAA->SetI(10000);
  ASSERT_EQ(pAA->GetI(), 10000);

  delete pAA;
  pAA = stk.Pop();
  delete pAA;
  pAA = stk.Pop();
  delete pAA;
}

TEST_F(Test_tpl_stack, Push_Pop) {
  stk.Push(new AA(1));
  stk.Push(new AA(2));
  AA* pAA = stk.Pop();
  ASSERT_NE(pAA, nullptr);
  ASSERT_EQ(pAA->GetI(), 2);
  stk.Push(pAA);
  pAA = stk.Pop();
  ASSERT_EQ(pAA->GetI(), 2);
  stk.Push(pAA);
  pAA = stk.Pop();
  ASSERT_EQ(pAA->GetI(), 2);

  delete pAA;
  pAA = stk.Pop();
  delete pAA;

  pAA = stk.Pop();
  ASSERT_EQ(pAA, nullptr);
  pAA = stk.Pop();
  ASSERT_EQ(pAA, nullptr);
}

/*
TEST_F(Test_tpl_stack,Remove){
    stk.Push(new AA(1));
    AA* pAA=new AA(2); stk.Push(pAA);
    stk.Push(new AA(3));

    bool b{false};
    b=stk.Remove(pAA);
    ASSERT_EQ(b,true);
    ASSERT_EQ(stk.GetSize(),2);
    delete pAA;/// delete yourself, queue has no right to delete;
    b=stk.Remove(nullptr);
    ASSERT_EQ(b,false);
    ASSERT_EQ(stk.GetSize(),2);
    pAA=new AA(1000);
    b=stk.Remove(pAA);
    ASSERT_EQ(b,false);
    ASSERT_EQ(stk.GetSize(),2);
    delete pAA;


    pAA=stk.Pop();
    delete pAA;
    pAA=stk.Pop();
    delete pAA;
}
*/

TEST_F(Test_tpl_stack, PushAndPop_1000000_TimeCost) {
  const int M{1000000};
  for (int i = 0; i < M; ++i) {
    stk.Push(new AA(i));
  }
  ASSERT_EQ(stk.GetSize(), M);
  for (int i = 0; i < M; ++i) {
    AA* pAA = stk.Pop();
    delete pAA;
  }
}

#endif
